import java.net.*;
import java.util.ArrayList;
import java.io.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Container;
import java.awt.Graphics;

/**
 * This is the main server Class. Creates one socket listening for incoming
 * new connections.
 * 
 * When a new client connects it creates a separate thread handling that
 * specific client.
 * 
 * It keeps a list of all connected clients and contains methods for sending
 * messages bound for all connected clients.
 * 
 * 
 * @author Fredrik Wallenius
 *
 */
public class Server {
	public static String SERVER_VERSION = "1.0";
	
	private ServerSocket serverSocket = null;
	private boolean serverRunning = true;
	private ArrayList<ThreadedClient> currentClients;
	
	private mainPanel panel;
	
	Server(){	
		currentClients = new ArrayList<ThreadedClient>();
		try {
            serverSocket = new ServerSocket(4444);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 4444.");
            System.exit(-1);
        }
        
        this.initiateGUI();
		
		System.out.println("Server running..\n");
		
		try{
	        while (serverRunning){
		    	new ThreadedClient(serverSocket.accept(), this).start();
	        }
	        serverSocket.close();
		} catch(IOException ioe){
			ioe.printStackTrace();
		}
	}
	
	private void initiateGUI(){
		JFrame frame = new JFrame("OPS Chat server, version: " + SERVER_VERSION);
		
		panel = new mainPanel();
	    Container c = frame.getContentPane();
	    c.add(panel);
	    
	    frame.setSize(300, 200);
	    frame.setLocation(200, 25);
	    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	    frame.setVisible(true);
		
	}
	
	class mainPanel extends JPanel {
		public String lastmsg = null;

		public void paintComponent(Graphics g) {
		    super.paintComponent(g); 
		    g.drawString("OPS (One Pretty Simple) Chat server", 10, 15);
		    g.drawString("by Fredrik Wallenius & Peter Steiner 2009", 10, 30);
		    
		    g.drawString("Listening on port: " + serverSocket.getLocalPort(), 10, 60);
		    synchronized (currentClients){
		    	g.drawString("Connected clients: " + currentClients.size(), 10, 75);
		    }
		    if(lastmsg!=null){
		    	g.drawString("Last message sent was:", 10, 105);
		    	g.drawString(lastmsg, 10, 120);
		    }
		}
	}
	
	public void registerClient(ThreadedClient c){
		synchronized (currentClients){
			System.out.println("Adding socket ..");
			currentClients.add(c);
		}
		panel.repaint();
		this.sendUserList();
	}
	
	public void removeClient(ThreadedClient c){
		synchronized (currentClients){
			System.out.println("Removing socket from list..");
			currentClients.remove(c);
		}
		panel.repaint();
		this.sendUserList();
	}
	
	private void sendUserList(){
		StringBuilder sb = new StringBuilder(ServerProtocol.USERLIST_CMD);
		synchronized (currentClients){
			for(ThreadedClient c : currentClients)
				sb.append(ServerProtocol.parameterize(c.getClientName()));
			
			for(ThreadedClient c : currentClients)
				c.send(sb.toString());
		}
	}
	
	/** Formats the message to be sent according to the current protocol
	 * class and then sends it to all currently connected clients.
	 * 
	 * @param msg The message to be sent.
	 */
	public void sendAll(String msg, String senderName){
		synchronized (currentClients){
			for(ThreadedClient c : currentClients){
				c.send(ServerProtocol.formatBroadCast(msg, c.getMyBatchNo(true), senderName));		
			}
		}
		panel.lastmsg = senderName + ": " + msg;
		panel.repaint();
	}
}
